[None][perf] wrap up eagle changes in m3 side branch - #18066
Conversation
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Both arms now run Inferact/MiniMax-M3-EAGLE3-GQA, the head production
is moving to: same training data as the MHA head with the drafter's
attention changed from 64 to 4 KV heads, so its draft KV cache is 16x
smaller and matches the target's head count.
Measured on this branch (4-GPU node, InferenceMAX eval + the shared
chat-GSM8K acceptance probe):
aggregated (separate draft manager) 3.515 / 0.838, accuracy 95.45
disaggregated (unified sub-page view) 3.369 / 0.790, accuracy 95.15
3.395 / 0.798, accuracy 95.45
The aggregated figure is indistinguishable from the MHA card's GSM8K
reference (3.518 / 0.839), which is why that reference stands in for
the GQA card's missing GSM8K entry; the two cards agree on the
benchmark they do share (MT-Bench 2.698 vs 2.668). The disaggregated
arm measures ~0.14 lower, so the rate floor drops 0.78 -> 0.76 for
headroom while the length floor stays at 3.3 — still between the
measured healthy range and the 3.33 plateau a drafter-KV transfer
regression produced on this workload.
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
(cherry picked from commit af6ddb1)
Make graph exit depend on the latest mutation of every in-place target, including void side effects that are not reachable from the FX return value. This prevents an auxiliary-stream Eagle hidden-state capture from racing the graph-external speculative worker. Add a structural scheduler test covering the event and wait inserted before graph output. Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
6d627d7 to
e7c9ec9
Compare
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
38437d9 to
6ac0cb8
Compare
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
MiniMaxM3DraftKVCacheView required the shared pool's page-index scale to equal the draft layer's flat-pool slot stride, then reused that pool-level scale for its own block table. The pool scale counts the pool's first layer's pages per slot, so on the hybrid NVFP4 KV cache (NVFP4 sparse target layers plus the dense FP8 draft layer) the two differ: the AgentX CTX TP2 geometry reports index_scale 171 against a draft slot stride of 8, and every worker failed at warmup with "native P128 draft block-table mapping is unavailable". The view is rooted at the draft layer's K page, and get_kv_subpage_pool already returns the layer-local stride that puts slot s's K at s * stride and its V at s * stride + 1. Use that stride as the view's index scale and drop the pool-scale equality check; the single-layer, P128, kv_offset == 1 and stream checks remain. Uniform pools yield the same value as before, so homogeneous configurations are unchanged. The hybrid-view unit test now gives the source pool a scale that differs from the draft stride, and the geometry rejection test covers kv_offset. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Remove code that the native P128 draft view made unreachable or redundant: - MiniMaxM3KVCacheManagerV2 no longer declares draft_manager_kv_cache_dtype or supports_shared_draft_layers; the executor forces the unified target cache for MiniMax-M3, so no separate draft manager is ever built, and the base class already defaults to shared draft layers. - KvCacheCreator drops the draft_manager_tokens_per_block hook, which has no remaining definer. - MiniMaxM3DraftKVCacheView.copy_batch_block_offsets keeps the V2 padding as is instead of clamping padded V entries to slot 0's V page; both choices address the same valid slot-0 memory, and the clamp cost one kernel launch per draft step. - _dense_kv_inputs returns only the query, pool and slot stride; the softmax scales are constants at the call site. - The view's error messages use the same "native P128 draft view" name as its docstring and startup log. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Every multi-stream runtime op (set_stream, record_event, wait_event, record_stream) is gated by do_multi_stream(), which only the CUDA-graph runner enables during capture. A disaggregated context worker runs the piecewise torch.compile path without the CUDA-graph runner, so the flag is never set there: a probe on the production MiniMax-M3 context config showed set_stream, eagle_hidden_states_copy and wait_for_captured_hidden_states all executing with do_multi_stream=False. The publication event was therefore never recorded or waited on, and the extra custom op, event plumbing, private config flag and scheduler priority edge had no runtime effect. Remove them; the last capture goes back through inplace_slice_copy like the others. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
|
/bot run |
|
PR_Github #71084 [ run ] triggered by Bot. Commit: |
|
PR_Github #71084 [ run ] completed with state |
|
The multi-stream scheduler rebuilds the FX graph from its stream assignment. An in-place op that mutates a graph input without returning a value (Eagle3 captures decoder hidden states into a preallocated buffer with inplace_slice_copy) has no path to the FX output, so the scheduler could emit it after the output node, where it is dead code once the module is recompiled. On the MiniMax-M3 disaggregated context worker (piecewise torch.compile, max_num_streams 3) this dropped the final hidden-state capture and lowered Eagle3 acceptance from 3.48 to 3.24 on GSM8K; aggregated serving with the same compile settings measured 2.98. Make graph exit depend on the last mutation of every in-place target. The mutation is then emitted before output, and when auxiliary streams are live the exit also waits on the mutating stream before a graph-external consumer reads the buffer. This replaces the Eagle-specific priority edge with a general dependency and needs no model-specific op, event or configuration gate. Restore the scheduler unit test and extend it to assert that every capture precedes output, including captures of the last decoder layer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
a3abd6e to
343310a
Compare
|
@peihu-nv Both points are right, thanks — they led to the actual root cause.
|
|
/bot run |
|
PR_Github #71362 [ run ] triggered by Bot. Commit: |
|
PR_Github #71362 [ run ] completed with state |
Summary
This PR does all followings things in one PR to wrap up eagle works:
max_num_streams > 1: the multi-stream scheduler could emit the last hidden-state capture after the graph output, so the drafter read a stale slice (disagg AL 3.25 -> 3.48; aggregated + PCG 2.98 -> 3.49). Fixed inauto_multi_stream.py; the earlier event-based publication path never executed and has been removed.paths)
After this PR, the agg pareto curve change from green curve to red curve. But this PR is not expected to boost perf for disagg.

Correctness
AgentX Agg pareto perf testing